package abcy.cloud.authenticationserver.services.impls;


import abcy.cloud.authenticationserver.dto.req.*;
import abcy.cloud.authenticationserver.dto.resp.LoginUserResp;
import abcy.cloud.authenticationserver.dto.resp.SysUserSelectRespDto;
import abcy.cloud.authenticationserver.entities.OauthAccessToken;
import abcy.cloud.authenticationserver.entities.SysLoginLog;
import abcy.cloud.authenticationserver.mappers.OauthAccessTokenMapper;
import abcy.cloud.authenticationserver.mappers.SysLoginLogMapper;
import abcy.cloud.authenticationserver.services.LoginService;
import abcy.cloud.authenticationserver.util.Base64Util;
import abcy.cloud.blogcommon.builder.TypeBuilder;
import abcy.cloud.blogcommon.constant.LoginConstant;
import abcy.cloud.blogcommon.utils.CodeUtil;
import abcy.cloud.blogcommon.utils.UUIDUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import springfox.documentation.swagger2.mappers.ModelMapper;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class LoginServiceImpl implements LoginService {

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private SysLoginLogMapper sysLoginLogMapper;

    @Autowired
    private Ip2regionSearcher ip2regionSearcher;

    @Autowired
    private OauthAccessTokenMapper oauthAccessTokenMapper;


    @Override
    public Map<Object, Object> doLogin(SysLoginUserReq sysLoginUserReq, HttpServletRequest req) {
        SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
        Map<Object, Object> map = new HashMap<>();
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
        formData.add("username", sysLoginUserReq.getUserName());
        SysUserSelectReqDto sysUserSelectReqDto = new SysUserSelectReqDto();
        sysUserSelectReqDto.setUsername(sysLoginUserReq.getUserName());
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        String urlStr = "http://localhost:" + 8888 + "/sys/sysuser/getUserInfoByUserName";

        HttpEntity<SysUserSelectReqDto> entity = new HttpEntity<>(sysUserSelectReqDto, headers);
        Map<?, ?> result = restTemplate.exchange(urlStr, HttpMethod.POST,
                entity, Map.class).getBody();
        if(Objects.isNull(result)) {
            map.put("code", 999999);
            map.put("message", "用户名不存在，请输入正确的用户名");
            return map;
        }
        map.put("loginSign", "blog");
        LoginUserResp loginUserResp = new LoginUserResp();
        BeanUtils.copyProperties(sysLoginUserReq, loginUserResp);

        map.put("userId", result.get("id").toString());
        map.put("username", sysLoginUserReq.getUserName());
        map.put("password", sysLoginUserReq.getPassword());
        map.put("client_id", LoginConstant.CLIENT_ID);
        map.put("client_secret",LoginConstant.CLIENT_SECRET);
        map.put("grant_type",LoginConstant.GRANT_TYPE);
        map.put("source", sysLoginUserReq.getSource());
        //map.put("loginUserResp", loginUserResp);
        try {
            String access_token = getOAuthToken(map);
            map.put("access_token", access_token);
            Map<String, Object> map1 = new HashMap<>();
            map1.put("userId", result.get("id").toString());
            Map<?, ?> permissionResult = restTemplate.exchange("http://localhost:" + 8888 + "/sys/syspermission/getPermissions", HttpMethod.POST,
                    new HttpEntity<>(map1, headers), Map.class).getBody();
            List<String> list = (List<String>) permissionResult.get("permissions");
            map1.put("permissions", list);

            Map<?, ?> roleResult = restTemplate.exchange("http://localhost:" + 8888 + "/sys/sysrole/selectRolesByUserId", HttpMethod.POST,
                    new HttpEntity<>(map1, headers), Map.class).getBody();
            List<String> roleList = (List<String>) roleResult.get("roleList");
            map1.put("roles", roleList);
            redisTemplate.opsForValue().set("userInfo", map1, 36000000, TimeUnit.MILLISECONDS);

        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        String maxCode = sysLoginLogMapper.getMaxCode();
        sysLoginLogMapper.insert(TypeBuilder.of(SysLoginLog::new)
                .with(SysLoginLog::setCode, CodeUtil.codeGenerator("loginlog", maxCode))
                .with(SysLoginLog::setId, UUIDUtil.UUID()).with(SysLoginLog::setLoginUserId, "")
                .with(SysLoginLog::setLastLoginTime, new Date())
                .with(SysLoginLog::setLoginIp, sysLoginUserReq.getLoginIp()).with(SysLoginLog::setLoginAddress, ip2regionSearcher.getAddress(sysLoginUserReq.getLoginIp())).build());

        return map;
    }

    private String getOAuthToken(Map<Object, Object> map) throws JsonProcessingException {
        String pass = map.get("password").toString();
        String clisec = map.get("client_secret").toString();
        String username = map.get("username").toString();
        String clientId = map.get("client_id").toString();
        String grantType = map.get("grant_type").toString();
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
        formData.add("username", username);
        formData.add("password", pass);
        formData.add("client_id", "abcy");
        formData.add("client_secret", "abcy");
        formData.add("grant_type", grantType);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        String urlStr = "http://localhost:8082/oauth/token";
        /*Map<?,?> resultMap1 = (Map<?, ?>) restTemplate.exchange(urlStr, HttpMethod.POST,
                new HttpEntity<MultiValueMap<String, String>>(formData, headers), Map.class);*/
        Map<?, ?> resultMap = restTemplate.exchange(urlStr, HttpMethod.POST,
                new HttpEntity<MultiValueMap<String, String>>(formData, headers), Map.class).getBody();
        if (null != resultMap) {
            String accessToken = resultMap.get("access_token").toString();
            String refreshToken = resultMap.get("refresh_token").toString();
            String password = Base64Util.encodeData(pass);

            String clientSecret = Base64Util.encodeData(clisec);
            try {


                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
                String loginTime = sdf.format(date);
                String createDate = sdf1.format(date);
                OauthAccessTokenAddReq oauthAccessTokenAddReq = new OauthAccessTokenAddReq();
                OauthAccessToken oauthAccessToken = new OauthAccessToken();
                oauthAccessTokenAddReq.setToken(accessToken);
                oauthAccessTokenAddReq.setTokenId(UUIDUtil.UUID());
                oauthAccessTokenAddReq.setRefreshToken(refreshToken);
                oauthAccessTokenAddReq.setCreateDate(createDate);
                oauthAccessTokenAddReq.setLoginTime(loginTime);
                oauthAccessTokenAddReq.setUserName(username);
                oauthAccessTokenAddReq.setClientId(clientId);
                BeanUtils.copyProperties(oauthAccessTokenAddReq, oauthAccessToken);
                OauthAccessTokenSelectReq oauthAccessTokenSelectReq = new OauthAccessTokenSelectReq();
                oauthAccessTokenSelectReq.setUsername(username);
                oauthAccessTokenSelectReq.setCreateDate(createDate);
                OauthAccessTokenUpdateReq oauthAccessTokenUpdateReq = new OauthAccessTokenUpdateReq();
                oauthAccessTokenUpdateReq.setUsername(username);
                oauthAccessTokenUpdateReq.setRefreshToken(refreshToken);
                oauthAccessTokenUpdateReq.setToken(accessToken);
                oauthAccessTokenUpdateReq.setLoginTime(loginTime);
                String rToken = oauthAccessTokenMapper.getRefreshToken(oauthAccessTokenSelectReq);
                if(Objects.isNull(rToken)) {
                    oauthAccessTokenMapper.insert(oauthAccessToken);
                }else {
                    oauthAccessTokenMapper.updateRefreshToken(oauthAccessTokenUpdateReq);
                }

                System.out.println(refreshToken);
                //setRefreshToken(map.get("userId").toString(), resultMap.get("refresh_token").toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return accessToken;
        }
        return null;

    }
}
